package com.black.cat.jvm.classpath;

import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @Author blackcat
 * @create 2021/8/11 14:23
 * @version: 1.0
 * @description:类路径加载
 */
@Slf4j
public class Classpath {

    private Entry bootstrapClasspath;  //启动类路径

    private Entry extensionClasspath;  //扩展类路径

    private Entry userClasspath;       //用户类路径

    public Classpath(String jreOption, String cpOption) {
        //启动类&扩展类
        bootstrapAndExtensionClasspath(jreOption);
        //用户类
        parseUserClasspath(cpOption);
    }

    private void bootstrapAndExtensionClasspath(String jreOption) {
        //获取jre 目录
        String jreDir = getJreDir(jreOption);

        //..jre/lib/*
        String jreLibPath = Paths.get(jreDir, "lib") + File.separator + "*";
        bootstrapClasspath = EntryFactory.create(jreLibPath);

        //..jre/lib/ext/*
        String jreExtPath = Paths.get(jreDir, "lib", "ext") + File.separator + "*";
        extensionClasspath = EntryFactory.create(jreExtPath);

    }

    private static String getJreDir(String jreOption) {
        //优先使用用户-Xjre的参数
        if (jreOption != null && Files.exists(Paths.get(jreOption))) {
            return jreOption;
        }
        //如果没有输入-Xjre的参数,则在当前目录下寻找jre
        if (Files.exists(Paths.get("./jre"))) {
            return "./jre";
        }
        //还是找不到，使用JAVA_HOME环境变量
        String jh = System.getenv("JAVA_HOME");
        if (jh != null) {
            return Paths.get(jh, "jre").toString();
        }
        throw new RuntimeException("Can not find JRE folder!");
    }


    private void parseUserClasspath(String cpOption) {
        //如果没有配置"-cp", "-classpath" 则把当前目录作为用户目录路径
        if (cpOption == null) {
            cpOption = ".";
        }
        userClasspath = EntryFactory.create(cpOption);
    }

    public byte[] readClass(String className) throws Exception {
        className = className + ".class";

        //[readClass]启动类路径
        try {
            return bootstrapClasspath.readClass(className);
        } catch (Exception ignored) {
            //ignored
            log.info("bootstrapClasspath ignore");
        }

        //[readClass]扩展类路径
        try {
            return extensionClasspath.readClass(className);
        } catch (Exception ignored) {
            //ignored
            log.info("extensionClasspath ignore");
        }

        //[readClass]用户类路径
        return userClasspath.readClass(className);
    }

    public static void main(String[] agrs) {
        //UNIX下<code>'/'</code>，WIN 下<code>'\\'</code>.
        System.out.println(File.separator);
        //UNIX下<code>':'</code>，WIN 下<code>';'</code>
        System.out.println(File.pathSeparator);

        System.out.println(getJreDir(null));
        Classpath classpath = new Classpath(null, "D:\\develop\\code\\jjvm\\jvm-02\\target\\classes");
        try {
            //java.lang.Object
            String className = "com.black.cat.jvm.MainTest".replace(".", "/");
            log.info(className);
            byte[] classData = classpath.readClass(className);
            System.out.println("classData：");
            for (byte b : classData) {
                //16进制输出
                System.out.print(String.format("%02x", b & 0xff) + " ");
            }
            System.out.println();
        } catch (Exception e) {
            System.out.println("Could not find or load main class ");
            e.printStackTrace();
        }
    }
}
